package com.easylinkin.linkappapi.reportCenter.timer;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.alarm.entity.AlarmVo;
import com.easylinkin.linkappapi.alarm.mapper.AlarmMapper;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.device.dao.SprayRecordsMapper;
import com.easylinkin.linkappapi.device.dao.WaterRecordsMapper;
import com.easylinkin.linkappapi.device.dto.EnvironmentalAreaDTO;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.entity.SprayRecords;
import com.easylinkin.linkappapi.device.entity.WaterRecords;
import com.easylinkin.linkappapi.device.entity.vo.DeviceModelQueryVo;
import com.easylinkin.linkappapi.device.entity.vo.ElectricyRecordsVo;
import com.easylinkin.linkappapi.device.entity.vo.WaterRecordsVo;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.device.mapper.ElectricyRecordsMapper;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.device.service.EnvironmentalAreaService;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.inspection.mapper.ElectricBoxMapper;
import com.easylinkin.linkappapi.machinery.dto.MachineryIotDeviceDto;
import com.easylinkin.linkappapi.machinery.entity.ElevatorWorkRecord;
import com.easylinkin.linkappapi.machinery.entity.TowerCraneWorkRecord;
import com.easylinkin.linkappapi.machinery.mapper.ElevatorWorkRecordMapper;
import com.easylinkin.linkappapi.machinery.mapper.TowerCraneWorkRecordMapper;
import com.easylinkin.linkappapi.machinery.vo.MachineryDeviceVo;
import com.easylinkin.linkappapi.reportCenter.constant.AlarmEnum;
import com.easylinkin.linkappapi.reportCenter.entity.*;
import com.easylinkin.linkappapi.reportCenter.entity.vo.ReportAiVo;
import com.easylinkin.linkappapi.reportCenter.mapper.*;
import com.easylinkin.linkappapi.shigongyun.service.MachineryMonitorBiService;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.mapper.LinkappTenantMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Description 设备运行报告定时任务
 * @Author kan yuanfeng
 * @Date 2023/7/17 16:16
 */
@Component
public class DeviceReportTimer {
    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(DeviceReportTimer.class);

    @Autowired
    private LinkappTenantMapper linkappTenantMapper;
    @Autowired
    private ReportMapper reportMapper;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ReportDeviceMapper reportDeviceMapper;
    @Autowired
    private ReportAlarmMapper reportAlarmMapper;
    @Autowired
    private ReportEnergyMapper reportEnergyMapper;
    @Autowired
    private ReportMachineryMapper reportMachineryMapper;
    @Autowired
    private ReportSprayMapper reportSprayMapper;
    @Autowired
    private ReportAiMapper reportAiMapper;
    @Autowired
    private ReportAiDetailMapper reportAiDetailMapper;
    @Autowired
    private ReportElectricalMapper reportElectricalMapper;
    @Autowired
    private AlarmMapper alarmMapper;
    @Autowired
    private EnvironmentalAreaService environmentalAreaService;
    @Autowired
    private WaterRecordsMapper waterRecordsMapper;
    @Autowired
    private ElectricyRecordsMapper electricyRecordsMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private SprayRecordsMapper sprayRecordsMapper;
    @Autowired
    private DeviceAttributeStatusService deviceAttributeStatusService;
    @Autowired
    private ElectricBoxMapper electricBoxMapper;
    @Autowired
    private MachineryMonitorBiService machineryMonitorBiService;
    @Autowired
    private TowerCraneWorkRecordMapper towerCraneWorkRecordMapper;
    @Autowired
    private ElevatorWorkRecordMapper elevatorWorkRecordMapper;

    /**
     * 报告名称
     */
    private String reportName = "物联设备运行报告";

    /**
     * ai设备名称
     */
    private String AIDeviceTypeName = "AI识别主机";

    /**
     * 电气火灾设备名称
     */
    private String ElectricalDeviceTypeName = "电气火灾监测器";

    /**
     * 生成报告(每月1号8点定时生成运行报告)
     */
    @Scheduled(cron = "0 0 8 1 * ?")
    public void createReport(){
        try {
            LOGGER.info("------开始设备运行报告定时任务----------------start-----");
            //查询所有项目
            List<LinkappTenant> list = linkappTenantMapper.selectByProjectId(null);
            list.removeIf(l -> "1".equals(l.getId()));
            ExecutorService service = Executors.newFixedThreadPool(20);
            list.forEach(l -> {
                //报告的时间
                service.submit(()->{
                    createReport(l.getId(),null);
                });
                LOGGER.info("------完成设备运行报告定时任务----------------end-----");
            });
        } catch (Exception e) {
            LOGGER.error("------设备运行报告定时任务异常----------------error-----", e);
        }
    }

    /**
     * 生成报告
     * @param tenantId
     * @param time
     */
    @Transactional
    public void createReport(String tenantId, Date time) {
        Date date = new Date();
        if (null == time){
            time = DateUtil.offsetMonth(date, -1);
        }
        //报告生成
        Report report = new Report();
        report.setTenantId(tenantId);
        report.setName(DateUtil.format(time,"yyyy年MM月")+reportName);
        report.setCreateTime(date);
        report.setModifyTime(date);
        report.setStartTime(DateUtil.beginOfMonth(time));
        report.setEndTime(DateUtil.endOfMonth(time).offset(DateField.MILLISECOND,-999));
        reportMapper.insert(report);
        //物联网设备统计
        //设备数量统计
        List<ReportDevice> reportDevices = deviceMapper.countDeviceGlobal(tenantId);
        reportDevices.forEach(reportDevice ->{
            reportDevice.setTenantId(tenantId);
            reportDevice.setReportId(report.getId());
            reportDevice.setCreateTime(date);
            reportDevice.setModifyTime(date);
            reportDeviceMapper.insert(reportDevice);
        });
        //本月告警统计
        countAlram(tenantId, time, report.getId());

        //智能水电表统计
        countEnergy(tenantId, time, 1,report.getId());
        countEnergy(tenantId, time, 2,report.getId());

        //喷淋控制统计
        countSpray(tenantId,time, report.getId());

        //AI识别统计
        countAi(tenantId,time, report.getId());
        //电气火灾监测
        countElectrical(tenantId,time, report.getId());
        //塔吊监测
        countMachinery(tenantId, time, 1,report.getId());
        //升降机监测
        countMachinery(tenantId, time, 2,report.getId());
    }

    /**
     * 预警
     * @param tenantId
     * @param time
     * @param date
     * @param report
     */
    public List<ReportAlarm> countAlram(String tenantId, Date time, Integer reportId) {
        Date date = new Date();
        List<AlarmVo> alarmVos = alarmMapper.find4ReportGlobal(tenantId, time);
        List<ReportAlarm> sumList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(alarmVos)){
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.WATER,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.ELEC,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.DUST,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.FIRE,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.TOWER,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.LIFT,sumList);
            countAlarm(tenantId, reportId, alarmVos,AlarmEnum.DISCHARGE,sumList);
            //ai特殊处理
            List<AlarmVo> vos = alarmVos.stream().filter(a -> AIDeviceTypeName.equals(a.getDeviceTypeName())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(vos)){
                ReportAlarm reportAlarm = new ReportAlarm();
                reportAlarm.setNum(vos.size());
                reportAlarm.setType(AlarmEnum.AI.getType());
                reportAlarm.setReportId(reportId);
                reportAlarm.setTenantId(tenantId);
                reportAlarm.setCreateTime(date);
                reportAlarm.setModifyTime(date);
                if (null != reportId){
                    reportAlarmMapper.insert(reportAlarm);
                }else {
                    sumList.add(reportAlarm);
                }
            }
        }
        return sumList;
    }

    /**
     * 塔吊/升降机计算
     * @param tenantId
     * @param time
     * @param type
     * @param reportId
     */
    public List<ReportMachinery> countMachinery(String tenantId, Date time, Integer type, Integer reportId) {
        Date date = new Date();
        Map<String, List<TowerCraneWorkRecord>> listMap = new HashMap<>();
        //查询业务设备 QUIP_SJJ_02塔吊  QUIP_TSQZJ_01升降机
        MachineryDeviceVo machineryDeviceVo = new MachineryDeviceVo();
        machineryDeviceVo.setTypeCode(Integer.valueOf(1).equals(type)?"QUIP_TSQZJ_01":"QUIP_SJJ_02");
        machineryDeviceVo.setBinded(1);
        machineryDeviceVo.setTenantId(tenantId);
        List<MachineryIotDeviceDto> deviceDtos = machineryMonitorBiService.queryMachineryDevices(machineryDeviceVo);
        if (CollectionUtil.isNotEmpty(deviceDtos)) {
            Set<String> deviceCodes = deviceDtos.stream().filter(d -> CollectionUtil.isNotEmpty(d.getDeviceList()))
                    .flatMap(d -> d.getDeviceList().stream()).filter(de -> !"video".equals(de.getIotType()) && StringUtils.isNotBlank(de.getCode()))
                    .map(d -> d.getCode()).collect(Collectors.toSet());
            deviceCodes.forEach(d -> listMap.put(d, new ArrayList<>()));
        }
        //record表里的设备
        List<TowerCraneWorkRecord> towerCraneWorkRecords;
        if (Integer.valueOf(1).equals(type)){
            towerCraneWorkRecords = towerCraneWorkRecordMapper.find4Report(tenantId,time);
        }else {
            towerCraneWorkRecords = new ArrayList<>();
            List<ElevatorWorkRecord> elevatorWorkRecords = elevatorWorkRecordMapper.find4Report(tenantId, time);
            //转成一样的实体
            elevatorWorkRecords.forEach(e ->{
                TowerCraneWorkRecord craneWorkRecord = BeanUtil.toBean(e, TowerCraneWorkRecord.class);
                towerCraneWorkRecords.add(craneWorkRecord);
            });
        }

        //按设备分组
        if (CollectionUtil.isNotEmpty(towerCraneWorkRecords)){
            Map<String, List<TowerCraneWorkRecord>> map = towerCraneWorkRecords.stream().filter(w -> StringUtils.isNotBlank(w.getDeviceCode()))
                    .collect(Collectors.groupingBy(TowerCraneWorkRecord::getDeviceCode));
            map.forEach((k,v) -> listMap.put(k,v));
        }
        //查询告警次数
        String totalMaxContent = null;
        List<AlarmVo> alarmVos;
        if (listMap.size()>0){
            Set<String> dCodes = listMap.keySet();
            /**
             * 告警统计
             */
            alarmVos = alarmMapper.find4CountReportGlobal(tenantId,time,dCodes);
            //求出现最多次数的事件
            Map<String, List<AlarmVo>> totalMap = alarmVos.stream().filter(a -> StringUtils.isNotBlank(a.getRuleEngineName()))
                    .collect(Collectors.groupingBy(a -> a.getRuleEngineName()));
            totalMaxContent = getMaxContent(totalMap);
        } else {
            alarmVos = new ArrayList<>();
        }

            //汇总
        List<ReportMachinery> machineryList = new ArrayList<>();
        AtomicReference<Double> total = new AtomicReference<>((double) 0);
        listMap.forEach((k,v)->{
            ReportMachinery reportMachinery = new ReportMachinery();
            reportMachinery.setDeviceCode(k);
            //查询检测天数
            //查询检测天数
            int day = getFromEs(time, k, tenantId);
            reportMachinery.setDay(day);
            reportMachinery.setNum(v.size());
            double weight = v.stream().filter(item -> null != item.getMaxWeight()).mapToDouble(item -> item.getMaxWeight()).sum();
            reportMachinery.setWeight(weight);
            //工作时长
            Map<String, List<TowerCraneWorkRecord>> map = v.stream().collect(Collectors.groupingBy(item -> DateUtil.format(item.getEndTime(), "yyyy-MM-dd")));
            AtomicReference<Double> hour = new AtomicReference<>((double) 0);
            map.forEach((sk,sv)->{
               hour.updateAndGet(v1 -> new Double( (v1 + (double) (sv.get(sv.size() - 1).getEndTime().getTime() - sv.get(0).getStartTime().getTime()) / 3600000)));
            });
            reportMachinery.setHours(hour.get());
            //功效
            double sum = v.stream().mapToDouble(i -> (double)(i.getEndTime().getTime() - i.getStartTime().getTime())).sum();
            double shour = sum/3600000;
            total.updateAndGet(v1 -> new Double((v1 + shour)));
            reportMachinery.setEfficiency(sum==0?0:weight/shour);
            //告警次数
            List<AlarmVo> voList = alarmVos.stream().filter(a -> k.equals(a.getDeviceCode())).collect(Collectors.toList());
            reportMachinery.setAlarmNum(voList.size());
            if (voList.size() > 0){
                Map<String, List<AlarmVo>> smap = voList.stream().filter(item -> StringUtils.isNotBlank(item.getRuleEngineName())).collect(Collectors.groupingBy(AlarmVo::getRuleEngineName));
                //求最大值
                String maxContent = getMaxContent(smap);
                reportMachinery.setTopEvent(maxContent);
            }
            reportMachinery.setType(type);
            machineryList.add(reportMachinery);
        });
        if (machineryList.size() > 0){
            //排序
            List<ReportMachinery> reportMachineryList = machineryList.stream().sorted(Comparator.comparing(ReportMachinery::getNum).reversed()).collect(Collectors.toList());
            ReportMachinery reportMachinery = new ReportMachinery();
            //取最大的检测天数
            ReportMachinery machinery = machineryList.stream().max(Comparator.comparing(ReportMachinery::getDay)).get();
            reportMachinery.setDay(machinery.getDay());
            int sum = machineryList.stream().mapToInt(m -> m.getNum()).sum();
            reportMachinery.setNum(sum);
            double weight = machineryList.stream().mapToDouble(m -> m.getWeight()).sum();
            reportMachinery.setWeight(weight);
            double hours = machineryList.stream().mapToDouble(m -> m.getHours()).sum();
            reportMachinery.setHours(hours);
            //功效
            reportMachinery.setEfficiency(total.get()==0?0:weight/total.get());
            //告警次数
            int alarmNum = machineryList.stream().mapToInt(m -> m.getAlarmNum()).sum();
            reportMachinery.setAlarmNum(alarmNum);
            reportMachinery.setType(type);
            reportMachinery.setTopEvent(totalMaxContent);
            reportMachineryList.add(reportMachinery);
            if (null != reportId){
                reportMachineryList.forEach(water ->{
                    water.setCreateTime(date);
                    water.setCreateTime(date);
                    water.setReportId(reportId);
                    water.setTenantId(tenantId);
                    reportMachineryMapper.insert(water);
                });
            }else {
                return reportMachineryList;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 电气火灾计算
     * @param tenantId
     * @param time
     * @param reportId
     */
    public List<ReportElectrical> countElectrical(String tenantId, Date time, Integer reportId) {
//        ElectricBox electricBox = new ElectricBox();
//        electricBox.setTenantId(tenantId);
//        electricBox.setIsDelete(0);
//        IPage<ElectricBox> electricBoxIPage = electricBoxMapper.queryListByPage(new Page<>(1,-1), electricBox);

        //关联设备计算
        List<String> monitorDeviceCodes = electricBoxMapper.findMonitorDeviceCodes(tenantId);

        Date date = new Date();
        Map<String, List<AlarmVo>> listMap = new HashMap<>();
        monitorDeviceCodes.removeIf(m->StringUtils.isBlank(m));
        if (CollectionUtil.isNotEmpty(monitorDeviceCodes)){
            monitorDeviceCodes.forEach(code -> listMap.put(code,new ArrayList<>()));
        }
        //查询数据
        //查询AI数据
        String totalMaxContent = null;
        List<AlarmVo> alarmVos = alarmMapper.find4ReportAIGlobal(tenantId,time,ElectricalDeviceTypeName);
        if (CollectionUtil.isNotEmpty(alarmVos)){
            Map<String, List<AlarmVo>> map = alarmVos.stream().collect(Collectors.groupingBy(AlarmVo::getDeviceCode));
            map.forEach((k,v) -> listMap.put(k,v));

            //求出现最多次数的事件
            Map<String, List<AlarmVo>> totalMap = alarmVos.stream().filter(a -> StringUtils.isNotBlank(a.getRuleEngineName()))
                    .collect(Collectors.groupingBy(a -> a.getRuleEngineName()));
            totalMaxContent = getMaxContent(totalMap);
        }

        //汇总
        List<ReportElectrical> electricalList = new ArrayList<>();
        listMap.forEach((k,v)->{
            ReportElectrical reportElectrical = new ReportElectrical();
            reportElectrical.setDeviceCode(k);
            //查询检测天数
            int day = getFromEs(time, k, tenantId);
            reportElectrical.setDay(day);
            reportElectrical.setNum(v.size());
            //top告警时间
            if (v.size() > 0){
                Map<String, List<AlarmVo>> map = v.stream().filter(item -> StringUtils.isNotBlank(item.getRuleEngineName())).collect(Collectors.groupingBy(AlarmVo::getRuleEngineName));
                //求最大值
                String maxContent = getMaxContent(map);
                reportElectrical.setTopEvent(maxContent);
            }
            electricalList.add(reportElectrical);
        });
        if (electricalList.size() > 0){
            //取最大的检测天数
            ReportElectrical electrical = electricalList.stream().max(Comparator.comparing(ReportElectrical::getDay)).get();
            //次数
            int numSum = electricalList.stream().mapToInt(s -> s.getNum()).sum();
            ReportElectrical reportElectrical = new ReportElectrical();
            reportElectrical.setDay(electrical.getDay());
            reportElectrical.setNum(numSum);
            reportElectrical.setTopEvent(totalMaxContent);

            electricalList.add(reportElectrical);
            if (null != reportId){
                electricalList.forEach(e ->{
                    e.setCreateTime(date);
                    e.setCreateTime(date);
                    e.setReportId(reportId);
                    e.setTenantId(tenantId);
                    reportElectricalMapper.insert(e);
                });
            }else {
                return electricalList;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 求最大的事件值
     * @param map
     * @return
     */
    private String getMaxContent(Map<String, List<AlarmVo>> map) {
        AtomicInteger i = new AtomicInteger();
        map.forEach((k,v) ->{
            if (v.size() > i.get()){
                i.set(v.size());
            }
        });
        List<String> list = map.entrySet().stream().filter(m -> m.getValue().size() == i.get()).map(m -> m.getKey()).collect(Collectors.toList());
        String join = StringUtils.join(list, ",");
        return join;
    }

    /**
     * 计算喷淋设备
     * @param tenantId
     * @param time
     * @param reportId
     */
    public List<ReportAiVo> countAi(String tenantId, Date time, Integer reportId) {
        Date date = new Date();
        Map<String, List<AlarmVo>> listMap = new HashMap<>();
        //查询AI设备
        List<Device> deviceList = deviceMapper.countAIDeviceGlobal(tenantId,AIDeviceTypeName);
        if (CollectionUtil.isNotEmpty(deviceList)){
            deviceList.forEach(d->listMap.put(d.getCode(),new ArrayList<>()));
        }
        //查询AI数据
        List<AlarmVo> alarmVos = alarmMapper.find4ReportAIGlobal(tenantId,time,AIDeviceTypeName);
        if (CollectionUtil.isNotEmpty(alarmVos)){
            Map<String, List<AlarmVo>> map = alarmVos.stream().collect(Collectors.groupingBy(AlarmVo::getDeviceCode));
            map.forEach((k,v) -> listMap.put(k,v));
        }

        //汇总
        List<ReportAiVo> aiVoList = new ArrayList<>();
        listMap.forEach((k,v)->{
            ReportAiVo reportAiVo = new ReportAiVo();
            reportAiVo.setDeviceCode(k);
            //查天数
            int day = getFromEs(time, k, tenantId);
            reportAiVo.setDay(day);
            reportAiVo.setNum(v.size());
            //事件详情
            Map<String, List<AlarmVo>> detailMap = v.stream().filter(item -> StringUtils.isNotBlank(item.getContent()))
                    .collect(Collectors.groupingBy(AlarmVo::getContent));
            if (detailMap.size() > 0){
                List<ReportAiDetail> detailList = new ArrayList<>();
                detailMap.forEach((sk,sv) ->{
                    ReportAiDetail reportAiDetail = new ReportAiDetail();
                    reportAiDetail.setEvent(sk);
                    reportAiDetail.setNum(sv.size());
                    detailList.add(reportAiDetail);
                });
                reportAiVo.setDetailList(detailList);
            }
            aiVoList.add(reportAiVo);
        });
        if (aiVoList.size() > 0){
            //取最大的检测天数
            ReportAiVo dayReportSpray = aiVoList.stream().max(Comparator.comparing(ReportAiVo::getDay)).get();
            //喷淋次数
            int numSum = aiVoList.stream().mapToInt(s -> s.getNum()).sum();
            ReportAiVo reportAiVo = new ReportAiVo();
            reportAiVo.setDay(dayReportSpray.getDay());
            reportAiVo.setNum(numSum);
            //详情
            Map<String, List<ReportAiDetail>> sonMap = aiVoList.stream().filter(a -> CollectionUtil.isNotEmpty(a.getDetailList())).flatMap(a -> a.getDetailList().stream())
                    .collect(Collectors.groupingBy(ReportAiDetail::getEvent));
            if (sonMap.size() > 0){
                List<ReportAiDetail> detailList = new ArrayList<>();
                sonMap.forEach((sk,sv) ->{
                    ReportAiDetail reportAiDetail = new ReportAiDetail();
                    reportAiDetail.setEvent(sk);
                    int sum = sv.stream().mapToInt(s -> s.getNum()).sum();
                    reportAiDetail.setNum(sum);
                    detailList.add(reportAiDetail);
                });
                reportAiVo.setDetailList(detailList);
            }
            aiVoList.add(reportAiVo);
            if (null != reportId){
                aiVoList.forEach(ai ->{
                    ai.setCreateTime(date);
                    ai.setCreateTime(date);
                    ai.setReportId(reportId);
                    ai.setTenantId(tenantId);
                    ReportAi reportAi = BeanUtil.toBean(ai, ReportAi.class);
                    reportAiMapper.insert(reportAi);
                    //保存详情
                    if (CollectionUtil.isNotEmpty(ai.getDetailList())){
                        ai.getDetailList().forEach(d ->{
                            d.setCreateTime(date);
                            d.setCreateTime(date);
                            d.setReportId(reportId);
                            d.setTenantId(tenantId);
                            d.setLinkId(reportAi.getId());
                            reportAiDetailMapper.insert(d);
                        });
                    }

                });
            }else {
                return aiVoList;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 计算喷淋设备
     * @param tenantId
     * @param time
     * @param reportId
     */
    public List<ReportSpray> countSpray(String tenantId, Date time,Integer reportId) {
        Date date = new Date();
        Map<String, List<SprayRecords>> listMap = new HashMap<>();
        //查询设备
        DeviceModelQueryVo device = new DeviceModelQueryVo();
        device.setModelId(0);
        device.setModelCategory("spary");
        device.setTenantId(tenantId);
        List<Device> devices = deviceService.selectModelDevices(device);
        if (CollectionUtil.isNotEmpty(devices)){
            devices.stream().filter(d->StringUtils.isNotBlank(d.getCode()))
                    .map(d->d.getCode()).collect(Collectors.toSet()).forEach(code ->{
                        listMap.put(code,new ArrayList<>());
                    });
        }
        //查询数据
        List<SprayRecords> sprayRecords = sprayRecordsMapper.find4Report(tenantId,time);
        if (CollectionUtil.isNotEmpty(sprayRecords)){
            Map<String, List<SprayRecords>> map = sprayRecords.stream().collect(Collectors.groupingBy(SprayRecords::getDeviceCode));
            map.forEach((k,v) -> listMap.put(k,v));
        }

        //汇总
        List<ReportSpray> sprayList = new ArrayList<>();
        listMap.forEach((k,v)->{
            ReportSpray reportSpray = new ReportSpray();
            reportSpray.setDeviceCode(k);
            //喷淋时长
            double sum = v.stream().filter(item -> null != item.getSprayHours()).mapToDouble(item -> item.getSprayHours()).sum();
            reportSpray.setHours(sum);
            //通过天数再分组
            Map<String, List<SprayRecords>> map = v.stream().collect(Collectors.groupingBy(item -> DateUtil.format(item.getTriggerTime(), "yyyy-MM-dd")));
            reportSpray.setDay(map.size());
            //喷淋次数
            reportSpray.setNum(v.size());
            sprayList.add(reportSpray);
        });
        if (sprayList.size() > 0){

            //喷淋次数
            int numSum = sprayList.stream().mapToInt(s -> s.getNum()).sum();
            //喷淋时长
            double hourSum = sprayList.stream().mapToDouble(s -> s.getHours()).sum();
            ReportSpray reportSpray = new ReportSpray();
            //通过天数再分组
            Map<String, List<SprayRecords>> map = sprayRecords.stream().collect(Collectors.groupingBy(item -> DateUtil.format(item.getTriggerTime(), "yyyy-MM-dd")));
            reportSpray.setDay(map.size());
            reportSpray.setNum(numSum);
            reportSpray.setHours(hourSum);
            sprayList.add(reportSpray);
            if (null != reportId){
                sprayList.forEach(spray ->{
                    spray.setCreateTime(date);
                    spray.setCreateTime(date);
                    spray.setReportId(reportId);
                    spray.setTenantId(tenantId);
                    reportSprayMapper.insert(spray);
                });
            }else {
                return sprayList;
            }
        }
        return null;
    }

    /**
     * 计算水电消耗
     * @param tenantId
     * @param time
     * @param reportId
     * @param type 1水 2电
     */
    public List<ReportEnergy> countEnergy(String tenantId, Date time,Integer type, Integer reportId) {
        Date date = new Date();
        Map<String, List<WaterRecordsVo>> listMap = new HashMap<>();
        EnvironmentalAreaDTO environmentalAreaDTO = new EnvironmentalAreaDTO();
        environmentalAreaDTO.setType(type);
        environmentalAreaDTO.setTenantId(tenantId);
        List<EnvironmentalAreaDTO> areaDTOS = environmentalAreaService.queryTree(environmentalAreaDTO);
        Map<String, List<WaterRecordsVo>> finalListMap = listMap;
        if (CollectionUtil.isNotEmpty(areaDTOS)){
            Set<String> codes = areaDTOS.stream().filter(a -> CollectionUtil.isNotEmpty(a.getDeviceCodes()))
                    .flatMap(a -> a.getDeviceCodes().stream()).collect(Collectors.toSet());
            codes.forEach(code ->finalListMap.put(code,new ArrayList<>()));
        }

        //record表里的设备
        List<WaterRecordsVo> waterRecords;
        if (Integer.valueOf(1).equals(type)){
            waterRecords = waterRecordsMapper.findOneArea(tenantId, time);
        }else {
            waterRecords = new ArrayList<>();
            List<ElectricyRecordsVo> electricyRecords = electricyRecordsMapper.findOneArea(tenantId, time);
            //用电的转成用水实体
            electricyRecords.forEach(e ->{
                WaterRecordsVo waterRecordsVo = BeanUtil.toBean(e, WaterRecordsVo.class);
                waterRecordsVo.setWaterIncrement(e.getElectricyIncrement());
                waterRecords.add(waterRecordsVo);
            });
        }

        //按设备分组
        if (CollectionUtil.isNotEmpty(waterRecords)){
            Map<String, List<WaterRecordsVo>> map = waterRecords.stream().filter(w -> StringUtils.isNotBlank(w.getDeviceCode()))
                    .collect(Collectors.groupingBy(WaterRecords::getDeviceCode));
            map.forEach((k,v) -> finalListMap.put(k,v));
        }
        //汇总
        List<ReportEnergy> waterList = new ArrayList<>();
        finalListMap.forEach((k,v)->{
            ReportEnergy reportEnergy = new ReportEnergy();
            reportEnergy.setType(type);
            reportEnergy.setDeviceCode(k);
            //用水总量
            double sum = v.stream().filter(item -> null != item.getWaterIncrement()).mapToDouble(WaterRecords::getWaterIncrement).sum();
            reportEnergy.setNum(sum);
            //求区域名称
            EnvironmentalAreaDTO dto = areaDTOS.stream().filter(a -> k.equals(a.getDeviceCode())).findFirst().orElse(null);
            if (null != dto){
                reportEnergy.setAreaName(dto.getName());
            }else if (v.size() > 0){
                reportEnergy.setAreaName(v.get(0).getAreaName());
            }
            waterList.add(reportEnergy);
        });
        if (waterList.size() > 0){
            ReportEnergy reportEnergy = new ReportEnergy();
            //取最大的检测天数
            if (CollectionUtil.isNotEmpty(waterRecords)){
                DateTime startTime = DateUtil.beginOfDay(waterRecords.get(0).getCollectTime());
                DateTime endTime = DateUtil.beginOfDay(waterRecords.get(waterRecords.size()-1).getCollectTime());
                long l = DateUtil.betweenDay(startTime, endTime, false);
                reportEnergy.setDay((int)l+1);
            }else {
                reportEnergy.setDay(0);
            }
            //总用量
            double sum = waterList.stream().mapToDouble(w -> w.getNum()).sum();
            reportEnergy.setNum(sum);
            reportEnergy.setType(type);
            waterList.add(reportEnergy);
            if (null != reportId){
                waterList.forEach(water ->{
                    water.setCreateTime(date);
                    water.setCreateTime(date);
                    water.setReportId(reportId);
                    water.setTenantId(tenantId);
                    reportEnergyMapper.insert(water);
                });
            }else {
                return waterList;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 告警统计
     * @param tenantId
     * @param reportId
     * @param alarmVos
     */
    private void countAlarm(String tenantId, Integer reportId, List<AlarmVo> alarmVos,AlarmEnum alarmEnum,List<ReportAlarm> sumList) {
        //告警次数统计
        List<AlarmVo> voList = alarmVos.stream().filter(a -> StringUtils.isNotBlank(a.getRuleEngineName()) && a.getRuleEngineName().startsWith(alarmEnum.getRuleNamePre()))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(voList)){
            ReportAlarm reportAlarm = new ReportAlarm();
            reportAlarm.setNum(voList.size());
            reportAlarm.setType(alarmEnum.getType());
            reportAlarm.setReportId(reportId);
            reportAlarm.setTenantId(tenantId);
            reportAlarm.setCreateTime(new Date());
            reportAlarm.setModifyTime(new Date());
            if (null != reportId){
                reportAlarmMapper.insert(reportAlarm);
            }else {
                sumList.add(reportAlarm);
            }
        }
    }

    /**
     * 查询流水
     */
    private int getFromEs(Date time,String deviceCode,String tenantId){
        AtomicInteger num = new AtomicInteger();
        RequestModel<DeviceAttributeStatus> requestModel = new RequestModel<>();
        requestModel.setPage(new Page<>(1,1));
        DeviceAttributeStatus deviceAttributeStatus = new DeviceAttributeStatus();

        //查询检测天数
        deviceAttributeStatus.setDeviceCode(deviceCode);
        deviceAttributeStatus.setTenantId(tenantId);
        requestModel.setCustomQueryParams(deviceAttributeStatus);
        List<DateTime> times = DateUtil.rangeToList(DateUtil.beginOfMonth(time), DateUtil.endOfMonth(time), DateField.DAY_OF_YEAR);
        times.forEach(t->{
            deviceAttributeStatus.setQueryTimeStart(DateUtil.formatDateTime(DateUtil.beginOfDay(t)));
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.formatDateTime(DateUtil.endOfDay(t)));
            IPage<Map> iPage = deviceAttributeStatusService.getHistoricDataFromEs(requestModel);
            if (CollectionUtil.isNotEmpty(iPage.getRecords())){
                num.getAndIncrement();
            }
        });
        return num.get();
    }
}
